#!/usr/bin/env python3
"""
Weather Semantic Server — 最终版（语义检索 + 天气查询）

特性：
- 提供 semantic_read(question, top_k)：语义检索文档片段
- 提供 query_weather(city)：天气查询
- 不再包含旧的 read_and_query_document / get_document_summary 等文件处理方法

依赖：
  pip install -U fastmcp sentence-transformers numpy tqdm pypdf httpx python-dotenv

环境变量：
  DOCS_DIR=./documents
  EMBED_MODEL=sentence-transformers/all-MiniLM-L6-v2
  OPENWEATHER_API_BASE=https://api.openweathermap.org/data/2.5/weather
  WEATHER_KEY=your_api_key
  USER_AGENT=WeatherMCP/1.0 (+https://example.com)
"""
from __future__ import annotations

import os
import json
from typing import Any

from dotenv import load_dotenv
import httpx
from mcp.server.fastmcp import FastMCP

from semantic_index import SemanticIndex

load_dotenv()

# ---------- 配置 ----------
DOCS_DIR = os.getenv("DOCS_DIR", "./documents")
EMBED_MODEL = os.getenv("EMBED_MODEL", "sentence-transformers/all-MiniLM-L6-v2")

OPENWEATHER_API_BASE = os.getenv("OPENWEATHER_API_BASE", "https://api.openweathermap.org/data/2.5/weather")
API_KEY = os.getenv("WEATHER_KEY")
USER_AGENT = os.getenv("USER_AGENT", "WeatherMCP/1.0 (+https://example.com)")

# ---------- MCP 服务器 ----------
mcp = FastMCP("WeatherSemanticServer")

# ---------- 语义索引（单例） ----------
IDX = SemanticIndex(docs_dir=DOCS_DIR, model_name=EMBED_MODEL, persist_path="./.semantic_index.npz")
IDX.ensure_built()

@mcp.tool()
async def semantic_read(question: str, top_k: int = 5) -> str:
    """使用语义检索在 DOCS_DIR 内查找与 question 最相关的片段并返回。"""
    IDX.refresh_if_changed()
    hits = IDX.search(question, top_k=top_k)
    return IDX.format_hits(hits)

@mcp.tool()
async def semantic_refresh() -> str:
    """强制刷新索引（例如新增/替换文档后手动调用）。"""
    IDX.ensure_built(force=True)
    return f"✅ 已重建索引：共 {len(IDX.texts)} 个片段。"

# ---------- 天气查询 ----------
async def fetch_weather(city: str) -> dict[str, Any] | None:
    if not API_KEY:
        return {"error": "未配置 WEATHER_KEY"}
    params = {"q": city, "appid": API_KEY, "units": "metric", "lang": "zh_cn"}
    headers = {"User-Agent": USER_AGENT}
    async with httpx.AsyncClient() as client:
        try:
            resp = await client.get(OPENWEATHER_API_BASE, params=params, headers=headers, timeout=30.0)
            resp.raise_for_status()
            return resp.json()
        except httpx.HTTPStatusError as e:
            return {"error": f"HTTP 错误: {getattr(e.response,'status_code','unknown')}"}
        except Exception as e:
            return {"error": f"请求失败: {str(e)}"}

def format_weather(data: dict[str, Any] | str) -> str:
    if isinstance(data, str):
        try:
            data = json.loads(data)
        except Exception as e:
            return f"无法解析天气数据: {e}"
    if "error" in data:
        return f"⚠️ {data['error']}"
    city = data.get("name", "未知")
    country = data.get("sys", {}).get("country", "未知")
    temp = data.get("main", {}).get("temp", "N/A")
    humidity = data.get("main", {}).get("humidity", "N/A")
    wind_speed = data.get("wind", {}).get("speed", "N/A")
    weather_list = data.get("weather", [{}])
    description = weather_list[0].get("description", "未知")
    return (
        f"🌍 {city}, {country}\n"
        f"🌡 温度: {temp}°C\n"
        f"💧 湿度: {humidity}%\n"
        f"🌬 风速: {wind_speed} m/s\n"
        f"🌤 天气: {description}\n"
    )

@mcp.tool()
async def query_weather(city: str) -> str:
    """查询指定城市（英文）的天气并返回人类可读文本。"""
    data = await fetch_weather(city)
    return format_weather(data)

if __name__ == "__main__":
    mcp.run(transport='stdio')
